package com.czy.ekp.doc;

import cn.hutool.core.util.StrUtil;
import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.openxml4j.util.ZipSecureFile;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.docx4j.convert.in.xhtml.XHTMLImporterImpl;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Entities;
import org.jsoup.safety.Whitelist;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTRow;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblGrid;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTc;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTcPr;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.math.BigInteger;
import java.util.List;

public class DocUtils {


    /**
     * Jsoup默认提供五种白名单：
     *
     *   1)： none()
     *     该API会清除所有HTML标签，仅保留文本节点。
     *
     *   2)： simpleText()
     *     该API仅会保留b, em, i, strong, u 标签，除此之外的所有HTML标签都会被清除。
     *
     *   3)： basic()
     *     该API会保留 a, b, blockquote, br, cite, code, dd, dl, dt, em, i, li, ol, p, pre, q, small, span, strike, strong, sub, sup, u, ul 和其适当的属性标签，除此之外的所有HTML标签都会被清除，且该API不允许出现图片(img tag)。另外该API中允许出现的超链接中可以允许其指定http, https, ftp, mailto 且在超链接中强制追加rel=nofollow属性。
     *
     *   4)： basicWithImages()
     *     该API在保留basic()中允许出现的标签的同时也允许出现图片(img tag)和img的相关适当属性，且其src允许其指定 http 或 https。
     *
     *   5)： relaxed()
     *     该API仅会保留 a, b, blockquote, br, caption, cite, code, col, colgroup, dd, div, dl, dt, em, h1, h2, h3, h4, h5, h6, i, img, li, ol, p, pre, q, small, span, strike, strong, sub, sup, table, tbody, td, tfoot, th, thead, tr, u, ul 标签，除此之外的所有HTML标签都会被清除，且在超链接中不会强制追加rel=nofollow属性。
     */
    static final Whitelist user_content_filter = Whitelist.basicWithImages().addAttributes("span", "style");

    public static String cleanHtmlQuot(String htmlContent){
        if(StrUtil.isBlank(htmlContent)){
            return htmlContent;
        }

        // 这步是将html代码中转义的代码进行恢复， 从富文编辑提交过来的内容，会进行一个特殊字符转义
        // 去除本地图片(file://)或地址为空的图片,(?i)不区分大小写，  我的代码中去掉了，你可以不要
        String unescape = StringEscapeUtils.unescapeHtml4(htmlContent)
                .replaceAll("(?i)<img.*?src=[\\\"|\\']?((file://.*?)|(\\s*))[\\\"|\\']?\\s.*?>","");

        return Jsoup.clean(htmlContent, Whitelist.basicWithImages())
                .replace("windowtext","#000"); //windowtext 不识别，改成 #000
    }

    /**
     *  html 格式化，转成标准的 xhtml 格式
     *      1px＝0.75pt，常见的宋体9pt＝12px  pt=px乘以3/4。
     *      1mm约等于2.83pt,A4尺寸是21cm*29.7cm,所以应该是594.3pt*840.51pt
     * @param html
     * @return
     */
    public String html2xhtml(String html){
        //暂时不调用cleanHtmlQuot过滤，目前存在img.src属性被过滤没了的问题


        final Document htmldoc = Jsoup.parse( html);
        htmldoc.outputSettings().syntax(Document.OutputSettings.Syntax.xml).escapeMode(Entities.EscapeMode.xhtml);
        return htmldoc.html();//.replaceAll("(?i)(&#xa0;)|(&#160;)","&nbsp;");
    }

    /**
     * @param htmlBody
     * @return
     */
    public XWPFDocument html2WordDocument(String htmlBody){
        if(StringUtils.isBlank(htmlBody)){
            return null;
        }
        final String htmlContent = html2xhtml(htmlBody);

        try(ByteArrayOutputStream bos = new ByteArrayOutputStream()){

            WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.createPackage();
            XHTMLImporterImpl XHTMLImporterImpler = new XHTMLImporterImpl(wordMLPackage);
//            XHTMLImporterImpler.setXHTMLImageHandler(new XHTML2WordImageHandler(XHTMLImporterImpler));

//            延迟解析比率 ，解决报错:  java.io.IOException: Zip bomb detected!
//            参考  https://stackoverflow.com/questions/46796874/java-io-ioexception-failed-to-read-zip-entry-source
//            ZipSecureFile.setMinInflateRatio(-1.0d);
            wordMLPackage.getMainDocumentPart().getContent().addAll(XHTMLImporterImpler.convert(htmlContent,"http://localhost:8090/"));
            wordMLPackage.save(bos);

//            logger.info("tmpFile:{}", tmpFile.getAbsolutePath());
//            wordMLPackage.save(new File("/Users/tenney/Desktop/word.docx"));

            return verifyContent4MSOffice(new XWPFDocument(new ByteArrayInputStream(bos.toByteArray())));

        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     *  较验生成的内容是否符合微软office的格式要求
     * @param document
     * @return
     */
    public XWPFDocument verifyContent4MSOffice(XWPFDocument document){
        //较验表格
        /**
         *
         * <w:tbl>
         *         <w:tblPr>
         *             ....
         *         </w:tblPr>
         *         <w:tblGrid>
         *             <w:gridCol w:w="916"/>
         *             <w:gridCol w:w="1826"/>
         *             <w:gridCol w:w="3488"/>
         *             <w:gridCol w:w="3650"/>
         *             <w:gridCol w:w="1716"/>
         *             <w:gridCol w:w="1524"/>
         *         </w:tblGrid>
         *         <w:tr>
         *             <w:trPr>
         *                 <w:trHeight w:val="555" w:hRule="atLeast"/>
         *             </w:trPr>
         *             //  该处没有 tc(column)，将导致ms office打开报错
         *         </w:tr>
         *         <w:tr>
         *             <w:trPr>
         *                 <w:trHeight w:val="360" w:hRule="atLeast"/>
         *             </w:trPr>
         *             <w:tc>
         *                 <w:tcPr>
         *                     <w:tcW w:w="0" w:type="auto"/>
         *                     <w:gridSpan w:val="6"/>
         *                     <w:tcBorders/>
         *                     <w:tcMar>
         *                         <w:top w:w="11" w:type="dxa"/>
         *                         <w:left w:w="11" w:type="dxa"/>
         *                         <w:bottom w:w="15" w:type="dxa"/>
         *                         <w:right w:w="11" w:type="dxa"/>
         *                     </w:tcMar>
         *                     <w:vAlign w:val="center"/>
         *                 </w:tcPr>
         *                 <w:p>
         *                     <w:pPr>
         *                         <w:spacing w:after="269"/>
         *                         <w:ind w:left="225"/>
         *                         <w:jc w:val="left"/>
         *                     </w:pPr>
         *                     <w:r>
         *
         */
//        document.getDocument().getBody().getSectPr().getPgSz();
        document.getDocument().getBody().getTblList().forEach(tbl->{

//            tbl.getTblPr().getTblW().setW(BigInteger.valueOf(2000));
//            tbl.getTblPr().getTblW().setType(STTblWidth.DXA);
//            tbl.getTblPr().addNewTblStyle().setVal("StyledTable");

            CTTblGrid grid = tbl.getTblGrid();
            List<CTRow> rows = tbl.getTrList();
            try{
                rows.forEach(row->{
                    if(row.getTcList() == null || row.getTcList().isEmpty()){
                        CTTc tc= row.addNewTc();
                        tc.addNewP().addNewR().addNewT();
                        if(grid != null){
                            CTTcPr pr = tc.addNewTcPr();
                            pr.addNewGridSpan().setVal(BigInteger.valueOf(grid.getGridColList().size()));
                            tc.setTcPr(pr);
                        }
                    }
                });
            }catch (Exception e){
                e.printStackTrace();
            }
        });
        return document;
    }



}
